/**
 * Auteur : Dominique GUERIN
 * dominiquephDOTguerinATgmailDOT..
 * dominiqueDOTguerinATinseeDOTfr(ance)  
 * Remerciements: � Keith Brown pour ses deux livres sur la s�curit� sous Windows et ses diff�rents articles
 *                 et � Michel Barnett de Microsoft pour ses deux articles 
 *                ".NET Remoting Authentication and Authorization Sample"  et le code qui les accompagne
 *  Le code est utilisable, modifiable et redistribuable � volont� sous la condition de ne pas supprimer ces 7 lignes.
 */ 
 
 package fr.doume.cli.sspi;

//tomcat 5.5
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;

//tomcat 6
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import java.util.Date;

import fr.doume.cli.authenticator.Parameters;
import fr.doume.cli.authenticator.AuthenticationContext;
import fr.doume.cli.sspi.SSPException;
import java.io.IOException;
import java.lang.Short;
import java.util.Arrays;
import fr.doume.cli.Jvm2Cli;

  /**
  * Translation of the tomcat roles into SIDs.
  * These SIDs are compared with the sids in the access token, after each authentication
  */
public class TranslationRolesIntoSids
{
	private static Log log = LogFactory.getLog(TranslationRolesIntoSids.class);
/**
* arrray of sids send by getSids
*/  
	private byte[][] sids;
  
  private int sidsCount;
  
  /**
  * array of groups given before the translation.
  */  
	private String[] groups;

	/**
	* used by a cache of the translation
	*/
	private Date creationDate;

	private boolean translated;


  private Parameters parameters;
  
  private AuthenticationContext authenticationContext;
  /**
  *  Initialize the private fields. <code>sids</code> et <code>groups</code> are defined as array with a length = 0, 
  * <code>creationDate</code> is the Date of the creation of the instance, and <code>translated</code> is set to false.
  */
	public TranslationRolesIntoSids( AuthenticationContext ac)
	{
		
		parameters = ac.getParameters();
		authenticationContext = ac;
		sids = new byte[0][];
		sidsCount = 0;
		groups= new String[0];
		creationDate = new Date();
		translated = false;
	}

  /**
  *  This method calls <code>translateToSids</code> when translated is false, 
  * then calls <code>verifySids</code>.
  * After that <code>tarnslated</code> is set to true.
  * NegoServer returns an arry of SIDs, each SID is an array of bytes.
  * This array is only used by calls to the Windows API.
  */
	public int getSidsCount(String[] roles)
	throws SSPException
	{
    if (log.isDebugEnabled()) log.debug("Begin");
    if(!translated) 
    {
      if (log.isDebugEnabled()) log.debug("! translated");
      //if (sids.length == 0 && roles.length != 0)
      {
        if (! translateToSids( roles) )
        {
          throw new SSPException("Translation from roles to sids failed");
        }
      }
      groups = roles;
      translated = true;
      if( roles.length != sidsCount )
      {
        throw new SSPException("Count of tomcat roles != count of sids");
      }
    }//if(!translated)
		return sidsCount;
	}
	
	public String[] getGroups()
	{
    return groups;
  }
  
	public int getSidsCount()
	throws SSPException
	{
		if (sidsCount == 0 ){
      if( !translated)
			throw new SSPException("Count of roles is zero");
		}
		return sidsCount;
	}
	/**
	* Reurns a array of bytes array (the SIDs)
	*/
	public byte[][] getSids()
	throws SSPException
	{
		if (sidsCount == 0 ){
      if( !translated)
			throw new SSPException("Count of roles is zero");
		}
		return sids;
	}

	/**
	* Returns the creation Date of this instance
	*/
	public Date getDate()
	{
    return creationDate;
	}

  /**
  * Call NegoServer With an array of String (names of the groups).
  * Returns <code>false</code> if there is an error. 
  * In this case, the public method <code>getSids(roles)</code> throw an Exception. <br>
  * The array of SIDs is found by NegoServer :
  * <pre>
             <code>NTAccount temp = new NTAccount(new string(groups_with_headers, (int)position, (int)size_elem));
             si = (SecurityIdentifier)temp.Translate(typeof(SecurityIdentifier));</code>
  * </pre>
  * <pre>
  * Format of the message sent to Negoserver: (in BIG ENDIAN Unicode)
  *     count of char or short sent
  *     count of roles (short)
  *     for each role:
  *        length of the role (short)
  *        name of the role (array of char)
  * Before this message, there is the byte 0 : NegoServer translate the groups into sids.
  * If a socket is reused, you send before the byte 2
  * </pre> 
  */	
  private boolean translateToSids( String[] roles)
  throws SSPException
  {
    try
    {    
      Jvm2Cli t = new Jvm2Cli();
      sids = new byte[roles.length][];
    
      for (int i = 0; i< sids.length; i++)
      {
        sids[i] = t.TranslateNameIntoSid(roles[i]); 
      }
      sidsCount = sids.length;
    }
    catch(Exception e)
    {
      throw new SSPException("Exception: " + e.getMessage());
    }
    return true;
  }
  
  /**
  * Arrays.copyOfRange does not exist in the dans le JDK 6 mais pas dans le JDK 5: Remplace cette methode pour la compatilit� ascendante 
  */
  private byte[] copyarray(byte[] source, int from, int to)
  // replace Arrays.copyOfRange from jdk 6 for jdk 5
  {
    if ( from < 0  || from > source.length )
    {
      throw new java.lang.ArrayIndexOutOfBoundsException();
    }
    if ( from > to )
    {
      throw new java.lang.IllegalArgumentException();
    }
    
    byte[] target = new byte[to-from];
    for (int i = 0; i< to - from; i++)
    {
      target[i] = source[i + from];
    }
    return target;
  }


  public AuthenticationContext getAuthenticationContext()
  {
    return authenticationContext;
  }

  

}

